#include "../../HeadFiles/StandardHeads.h"
#include <conio.h>


#include "../../HeadFiles/ChainsH/RecordChain.h"
#include "../../HeadFiles/ChainsH/CommodityChain.h"
#include "../../HeadFiles/InputCheck.h"
#include "../../HeadFiles/GetTime.h"
#include "../../HeadFiles/UsedStd.h"
// #include "../HeadFiles/ClientChain.h"

// #define DEFAULT_UNIT_PRICE 1;
extern struct CommodityNode * commodityHead, * commodityTail, * commodityDisplayPtr;
void displayAllRecords(struct RecordNode * head, int opt)
{
    int idx = 0;
    while(head != NULL) {
        puts(SPLIT_STR);

        // 以下代码用来展示每个记录的细节信息， 做成代码块方便折叠
        {
            displayThisRecord(head);
        }
        if(opt == 1)
            head = head->nextRecord;
        else
            head = head->preRecord;
    }
    puts(SPLIT_STR);
    puts("Records Display Finished");
}

// 输出一个单一记录节点的信息
void displayThisRecord(struct RecordNode * recordDisplayPtr)
{
    // recordDisplayPtr是为了在主函数中区分不同的链表当前展示指针
    // 在函数里写成this方便阅读
    struct RecordNode * this = recordDisplayPtr;
    puts(SPLIT_STR);
    printf("Record Date(dd-mm-yyyy): %d-%d-%d\n", this->day, this->month, this->year);
    if(this->isSoldOut == true)
    {
        puts("Sale");
    }else{
        puts("Stock");
    }
    puts(SPLIT_STR);
    printf("Commodity: %s\n", this->commodityName);
    printf("purchasePrice(RMB): %.2f\n", this->purchasePrice);
    printf("SoldPrice(RMB): %.2f\n", this->soldPrice);
    printf("UnitCount(RMB): %d\n", this->unitCount);
    printf("Total(RMB) = %.2f\n", (this->purchasePrice) * (this->unitCount));

    printf("Client: %s\n", this->clientName);
    // printf("History Lv: %d\n", recordDisplayPtr->historyLv);
    puts(SPLIT_STR);
}


void buildRecordChain(struct RecordNode ** head, struct RecordNode ** tail)
{
    // 以只读模式打开文件
    FILE * recordFILE = fopen("../Data/RecordChainData/RecordData.txt", "r");

    * head = * tail = NULL; // 先初始化防止不操作返回野值
    int opt;
    fscanf(recordFILE, "%d", &opt); // opt==-1为停止添加节点，==1为添加新节点
    struct RecordNode * pre = NULL, * now = NULL;
    while(opt == 1)
    {
        now = (struct RecordNode *)malloc(sizeof(struct RecordNode));
        now->nextRecord = now->preRecord = NULL; // 申请完空间直接把指针初始化

        // 以下代码用来录入每个记录的细节信息， 做成代码块方便折叠
        {
            int temp;   // temp 用来给bool类型变量isSoldOut赋值
            fscanf(recordFILE, "%d", &temp);
            if(temp == 1)
                now->isSoldOut = true;
            else
                now->isSoldOut = false;
            fscanf(recordFILE, "%s", &now->commodityName);
            fscanf(recordFILE, "%s", &now->clientName);
            fscanf(recordFILE, "%lf", &now->purchasePrice);
            fscanf(recordFILE, "%lf", &now->soldPrice);
            fscanf(recordFILE,"%d", &now->unitCount);
            fscanf(recordFILE, "%d", &now->historyLv);
            fscanf(recordFILE, "%d %d %d", &now->day, &now->month, &now->year);
            // fscanf("")
        }

        if(* head == NULL)
        {
            * head = now;
        }else{
            pre->nextRecord = now;
            now->preRecord = pre;
        }
        pre = now;
        fscanf(recordFILE,"%d", &opt);
    }
    * tail = now;

    fclose(recordFILE);
    recordFILE = NULL;
}

void rebuildRecordFile(struct RecordNode * head)
{
    // 当增链表节点发生变化时，执行此函数，覆写record.txt文件
    // 注意是覆写
    FILE * recordFile = fopen("../Data/RecordChainData/RecordData.txt", "w");

    while(head != NULL)
    {
        // 输出节点所有信息的代码块，在测试时，暂时只输出unit count
        {
            fprintf(recordFile, "1\n");
            if(head->isSoldOut == true)
                fprintf(recordFile, "1\n");
            else
                fprintf(recordFile, "0\n");
            fprintf(recordFile, "%s\n", head->commodityName);
            fprintf(recordFile, "%s\n", head->clientName);
            fprintf(recordFile, "%.2f\n", head->purchasePrice);
            fprintf(recordFile, "%.2f\n", head->soldPrice);
            fprintf(recordFile, "%d\n", head->unitCount);
            fprintf(recordFile, "%d\n", head->historyLv);
            fprintf(recordFile, "%d %d %d\n", head->day, head->month, head->year);
            fprintf(recordFile, "\n");
            head = head->nextRecord;
        }
    }
    fputs("-1", recordFile);

    fclose(recordFile);
    recordFile = NULL;
}

void  delRecord(struct RecordNode ** head, struct RecordNode ** tail, struct RecordNode * p)
{
    // ** head, ** tail是头尾指针的地址，直接对其解引用，然后加以修改
    // 注意，p是指向节点的指针，和head，tail不一样
    if(* head == p || * tail == p)
    {
        // 如果要删除的节点比较特殊，是头或尾节点
        if(* head == p && * tail == p)
        {
            // 要删除的节点既是头又是尾， 此时链表只有这一个元素
            free(* head);

            //此部分为对Commodity中库存的影响，可能需要集成
            struct CommodityNode * searchPtr = commodityHead;
            while(searchPtr != NULL)
            {
                if(strcmp(searchPtr->commodityName, (*head)->commodityName) == 0)
                {
                    if((*head)->isSoldOut == true)
                        searchPtr->unitCount += (*head)->unitCount;
                    else if((*head)->isSoldOut == false)
                        searchPtr->unitCount -= (*head)->unitCount;
                }
                searchPtr = searchPtr->nextCommodity;
            }
            rebuildCommodityFile(commodityHead);

            * head = * tail = NULL; // free后内存被清理，但是指针仍指向该地址，必须置空防bug
            return ;
        }
        if(* head == p && * tail != p)
        {
            // 要删除的节点是头，但不是尾
            struct RecordNode * temp = * head;
            * head = (* head)->nextRecord;
            (* head)->preRecord = NULL;

            //此部分为对Commodity中库存的影响，可能需要集成
            struct CommodityNode * searchPtr = commodityHead;
            while(searchPtr != NULL)
            {
                if(strcmp(searchPtr->commodityName, temp->commodityName) == 0)
                {
                    if(temp->isSoldOut == true)
                        searchPtr->unitCount += temp->unitCount;
                    else if(temp->isSoldOut == false)
                        searchPtr->unitCount -= temp->unitCount;
                }
                searchPtr = searchPtr->nextCommodity;
            }
            rebuildCommodityFile(commodityHead);

            free(temp);
            return ;
        }
        if(* head != p && * tail == p)
        {
            // 要删除的节点是尾，但不是头
            struct RecordNode * temp = * tail;
            * tail = (* tail)->preRecord;
            (* tail)->nextRecord = NULL;

            //此部分为对Commodity中库存的影响，可能需要集成
            struct CommodityNode * searchPtr = commodityHead;
            while(searchPtr != NULL)
            {
                if(strcmp(searchPtr->commodityName, temp->commodityName) == 0)
                {
                    if(temp->isSoldOut == true)
                        searchPtr->unitCount += temp->unitCount;
                    else if(temp->isSoldOut == false)
                        searchPtr->unitCount -= temp->unitCount;
                }
                searchPtr = searchPtr->nextCommodity;
            }
            rebuildCommodityFile(commodityHead);

            free(temp);
            return ;
        }
    }
    // 如果删除的节点不是头或者尾的特殊情况
    // 注意，p是指向节点的指针，和head，tail不一样
    p->nextRecord->preRecord = p->preRecord;
    p->preRecord->nextRecord = p->nextRecord;

    //此部分为对Commodity中库存的影响，可能需要集成
    struct CommodityNode * searchPtr = commodityHead;
    while(searchPtr != NULL)
    {
        if(strcmp(searchPtr->commodityName, p->commodityName) == 0)
        {
            if(p->isSoldOut == true)
                searchPtr->unitCount += p->unitCount;
            else if(p->isSoldOut == false)
                searchPtr->unitCount -= p->unitCount;
        }
        searchPtr = searchPtr->nextCommodity;
    }
    rebuildCommodityFile(commodityHead);
    free(p);
}


void addRecord(struct RecordNode ** head, struct RecordNode ** tail)
{
    struct RecordNode * now = (struct RecordNode *) malloc(sizeof(struct RecordNode));
    now->preRecord = now->nextRecord = NULL;    // 申请新节点第一件事就是指针初始化！非常重要！

    if(* head == NULL && * tail == NULL)
    {
        // 增加链表第一个节点,该节点即是头又是尾
        puts("You are now creating the 1st Record");
        * head = * tail = now;

        // 输入具体信息的代码块
        // 此处应有比较复杂的非法输入检测
        {
            puts("Input 1 for a sold record & 0 for a purchase");
            char tempIsSoldOut = getche();
            while(!(tempIsSoldOut == '0' || tempIsSoldOut == '1'))
            {
                puts("Illegal input deteced!Try Again!");
                tempIsSoldOut = getche();
            }
            now->isSoldOut = (tempIsSoldOut == '1') ? true : false;
            puts("Input commodity name: ");
            scanf("%s", now->commodityName);
            puts("Input client name: ");
            scanf("%s", now->clientName);

            // 需要一个strToDouble函数！！！！
            puts("Input sold price:");
            scanf("%lf", &now->soldPrice);
            puts("Input purchase price: ");
            scanf("%lf", &now->purchasePrice);
            // 以上需要

            puts("Input unit count: ");
            char tempUnitCount[STR_MAX_LEN];
            scanf("%s", tempUnitCount);
            while(!(isFullDigit(tempUnitCount) && strlen(tempUnitCount) <= 8))
            {
                puts("Illegal input detected!try again: ");
                scanf("%s", tempUnitCount);
            }
            now->unitCount = strToInt(tempUnitCount);

            getCurrentTime(&now->year, &now->month, &now->day);
        }
        return ;
    }else{
        // 不是第一个节点，则只需接在最后节点(tail)的后面
        (* tail)->nextRecord = now;
        now->preRecord = * tail;
        * tail = now;

        // 输入具体信息
        // 此处应有比较复杂的非法输入检测
        {
            puts("Input 1 for a sold record & 0 for a purchase");
            char tempIsSoldOut = getche();
            while(!(tempIsSoldOut == '0' || tempIsSoldOut == '1'))
            {
                puts("Illegal input deteced!Try Again!");
                tempIsSoldOut = getche();
            }
            now->isSoldOut = (tempIsSoldOut == '1') ? true : false;
            puts("Input commodity name: ");
            scanf("%s", now->commodityName);
            puts("Input client name: ");
            scanf("%s", now->clientName);

            // 需要一个strToDouble函数！！！！
            puts("Input sold price:");
            scanf("%lf", &now->soldPrice);
            puts("Input purchase price: ");
            scanf("%lf", &now->purchasePrice);
            // 以上需要

            puts("Input unit count: ");
            char tempUnitCount[STR_MAX_LEN];
            scanf("%s", tempUnitCount);
            while(!(isFullDigit(tempUnitCount) && strlen(tempUnitCount) <= 8))
            {
                puts("Illegal input detected!try again: ");
                scanf("%s", tempUnitCount);
            }
            now->unitCount = strToInt(tempUnitCount);

            getCurrentTime(&now->year, &now->month, &now->day);
        }

        int flag = 0;//标记commdity链表中是否有完全相同的商品名
        struct CommodityNode * searchPtr = commodityHead;
        while(searchPtr != NULL)
        {
            if(strcmp(searchPtr->commodityName, now->commodityName) == 0)
            //对现有的商品进行修改
            {
                flag = 1;
                if(now->isSoldOut == true)
                    searchPtr->unitCount -= now->unitCount;
                else if(now->isSoldOut == false)
                    searchPtr->unitCount += now->unitCount;
            }
            searchPtr = searchPtr->nextCommodity;
        }
        if(flag == 0)//创建新的商品
        {
            struct CommodityNode * nowCommdity = (struct CommodityNode *) malloc(sizeof(struct CommodityNode));
            nowCommdity->preCommodity = nowCommdity->nextCommodity = NULL;    // 申请新节点第一件事就是指针初始化！非常重要
            // 不是第一个节点，则只需接在最后节点(tail)的后面
            commodityTail->nextCommodity = nowCommdity;
            nowCommdity->preCommodity = commodityTail;
            commodityTail = nowCommdity;
            // 输入具体信息
            {
                memcpy(nowCommdity->commodityName, now->commodityName, sizeof(now->commodityName));
                nowCommdity->soldPrice = now->soldPrice;
                nowCommdity->purchasePrice = now->purchasePrice;
                nowCommdity->unitCount = now->unitCount;
            }
            commodityDisplayPtr = commodityDisplayPtr->nextCommodity;
        }
        rebuildCommodityFile(commodityHead);
        return ;
    }
}
